#include "../include/EventLoop.hpp"

namespace wd{


EventLoop:: EventLoop(Acceptor &accept)
:_epfd(createEpollFd())
,_eventfd(createEventfd())
,_evArr(1000)
,_accept(accept)
,_isLooping(false)
,_mutex()
{
    addEpollReadEvent(_accept.fd());
    addEpollReadEvent(_eventfd);
}

EventLoop:: ~EventLoop(){}


void EventLoop::loop(){
    
    _isLooping = true;
    while(_isLooping){
         waitEpollFd();
    }
}

void EventLoop::unloop(){
    _isLooping = false;

}

void EventLoop::waitEpollFd(){

    int nready = epoll_wait(_epfd,_evArr.data(),_evArr.size(),3000);
    if(nready  == -1 && errno == EINTR){
        return;
    }else if(nready == -1){
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }else if(nready == 0){
        printf("epoll timeout\n");
    }else{
        
        for(int i = 0; i < nready; ++i){
           int fd = _evArr[i].data.fd;
           if(fd == _accept.fd()){
               handleNewConnection();
           }else if(fd == _eventfd){
                handleReadEvent();
                doPendingFunctors();

           }else{
               handleMessage(fd);
           }
        }
    }


}

void EventLoop::handleNewConnection(){
    int netfd = _accept.accept();
    
    //添加需要监听的事件
    addEpollReadEvent(netfd);
    
    //创建一个TcpConnection对象
    TcpConnectionPtr conn(new TcpConnection(netfd,this));

    //在TcpConnection对象中设置回调函数
    conn->setAllCallbacks(_onConnection,_onMessage,_onClose); 
    
    //建立netfd和Tcp连接对象之间的联系
    _conns.insert(std::make_pair(netfd,conn));

    //调用回调函数
    conn->handleNewConnectionCallback();

}

void EventLoop::handleMessage(int fd){
    auto iter = _conns.find(fd);
    if(iter != _conns.end()){
        bool isClosed = iter->second->isClosed();
        if(isClosed){
            iter->second->handleCloseCallback();
            delEpollReadEvent(fd);
            _conns.erase(fd);

        }else{
            iter->second->handleMessageCallback();
        }
    }
}




int EventLoop::createEpollFd(){
    
    int epfd = epoll_create1(0);
    if(epfd < 0){
        perror("epoll_create1");
        return EXIT_FAILURE;
    }

    return epfd;
}


int EventLoop::createEventfd(){
    int fd = eventfd(0,0);
    if(fd < 0){
        perror("eventfd");
    }
    return fd;
}
    
void EventLoop::addEpollReadEvent(int fd){
    
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&ev);
    if(ret < 0){
        perror("epoll_ctl");
    }


}
    
void EventLoop::delEpollReadEvent(int fd){
    struct epoll_event ev;
    ev.data.fd = fd;
    epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&ev);

}


void EventLoop::handleReadEvent(){
    uint64_t howmany = 0;
    int ret = read(_eventfd,&howmany,sizeof(howmany));
    if(ret != sizeof(howmany)){
        perror("read");
    }

}

void EventLoop::wakeup(){
    uint64_t one = 1;
    int ret = write(_eventfd,&one,sizeof(one));

    if(ret != sizeof(one)){
        perror("write");
    }

} 

void EventLoop::doPendingFunctors(){

    vector<Functor> tmp;
   
    {
        MutexLockGuard autolock(_mutex);
        tmp.swap(_pendingFunctors);
    }

    for(auto & f: tmp){
        f();
    }


}

void EventLoop::runInLoop(Functor && cb){

    {
        MutexLockGuard autolock(_mutex);
        _pendingFunctors.push_back(cb);
    }

    wakeup();


}



} //end of namespace wd

